"""
功能: 状态指示灯的类,封装了Timer类,用来来控制led的闪烁
最后更新: 250116

说明:
    主类为StatusLed,执行闪烁的各种任务,任务分两种
    常时: 一直运行的闪烁,可以是某个频率,也可以不闪烁(档位0)
    临时: 只执行一定时间的闪烁,结束后会切换到常时
    stop_status属性是不闪烁时的灯光状态,用来设置常熄还是常亮

    Scheduler类为调度器,记录一些参数

"""
import utime
from machine import Timer, Pin


# 调度器(常时任务的参数, 当前运行的任务类型)
class Scheduler():
    def __init__(self, position=0, delay=0, is_permanent=True):
        self.position = position  # 常时闪烁的档位
        self.delay = delay  # 临时闪烁的延时,毫秒
        self.is_permanent = is_permanent  # 是否在执行常时闪烁
        
    # 设置为执行常时闪烁
    def set_permanent(self, position=None):
        if position:
            self.position = position
        self.is_permanent = True
        
    # 设置为执行临时闪烁
    def set_temporary(self, delay):
        if delay and delay > 0:
            self.delay = delay
        self.is_permanent = False


# 
class StatusLed():
    def __init__(self, pin_no, period=1000, stop_status=0):
        self.led = Pin(pin_no, Pin.OUT)  # Pin对象       
        self.default_period = period  # 默认闪烁周期,毫秒
        self.stop_status = stop_status  # 停止时的状态, 0表示熄灭,1表示亮起
        self.scheduler = Scheduler()
        self.timer_blink = Timer()  # 闪烁用定时器
        self.timer_delay = Timer()  # 延时用定时器
        
        self.led.value(stop_status)  # 设置led的停止闪烁时的状态
    
    # -------------以下是基础方法----------------------
    # 回调函数,执行闪烁,传入的参数是Timer的要求
    def _do_blink(self, timer):
        self.led.toggle()
    
    # 回调函数,临时任务结束执行的代码(启动常时任务)
    def _do_delay(self, timer):
        self.blink_with_position(self.scheduler.position)
        self.scheduler.set_permanent()
            
    # 启动闪烁
    def start_blink(self, period, delay=0):
        """
        参数period: 闪烁周期
        参数delay: 延时, <=0表示不延时, 大于0表示延时毫秒数
        """
        if period > 0:
            if period > 10000 or period < 10:  # 超出范围,按默认周期闪烁
                period = self.default_period           
            self.timer_blink.init(period=period, mode=Timer.PERIODIC, callback=self._do_blink)

        
        else:  # 其他情况表明停止
            self.stop_blink()  
            
    # 停止闪烁
    def stop_blink(self):
        self.timer_blink.deinit()
        self.led.value(self.stop_status)  # 设置led的停止闪烁时的状态

    # 启动临时闪烁
    def start_delay(self, delay=1000, position=7):
        """
        参数delay: 延时时间,毫秒
        参数position: 闪烁档位
        """
        self.blink_with_position(position)
        self.timer_delay.init(period=delay, mode=Timer.ONE_SHOT, callback=self._do_delay)
    
    # 停止临时闪烁
    def stop_delay(self):
        self.timer_delay.deinit()
        self.stop_blink()
        
    # 按档位闪烁(不在列表中的档位一律当成0档)
    def blink_with_position(self, position):
        if position == 1:
            period = 4000    
        elif position == 2:
            period = 2000
        elif position == 3:    
            period = 1000
        elif position == 4:    
            period = 500
        elif position == 5:    
            period = 250
        elif position == 6:    
            period = 125
        elif position == 7:    
            period = 62
        elif position == 8:    
            period = 31
        else:
            period = 0
            
        self.start_blink(period)        


    
    # -------------以下是高级方法----------------------
    # 启动常时闪烁, 如果恢复上次的就无需传入档位参数
    def start_permanent(self, position=None):
        # 如果正在执行临时闪烁,先停止
        if not self.scheduler.is_permanent:
            self.stop_delay()
        
        # 如果传入档位,按该档位执行,否则使用调度器的(即上次的)
        if position:
            self.blink_with_position(position)
        else:
            self.blink_with_position(self.scheduler.position)
        
        self.scheduler.set_permanent(position)
    
    # 启动临时闪烁
    def start_temporary(self, position, delay):
        if delay >= 1000:
            # 如果正在执行临时闪烁,先停止
            if not self.scheduler.is_permanent:
                self.stop_delay()
                
            self.start_delay(delay, position)
            self.scheduler.set_temporary(delay)
        else:
            raise ValueError("延时太短:%d" % (delay,))
    
    
# 调试    
if __name__ == '__main__':
    green_led = StatusLed(25, stop_status=1)  # 实例化,设置为不闪烁时常亮
    utime.sleep(5)

#  按档位循环展示
#     for i in range(9):
#         print(f"档位:{i}")
#         green_led.blink_with_position(i)
#         utime.sleep(10)
#         
#     green_led.stop_blink()

# 常时
    print('执行常时任务')
    green_led.start_permanent(position=4)
    utime.sleep(5)

# 临时
    print('执行临时任务1')
    green_led.start_temporary(6, 8000)
    utime.sleep(2)  # 该临时任务尚未执行完就会被下面的覆盖

# 临时2
    print('执行临时任务2')
    green_led.start_temporary(8, 8000)
    print('临时任务2执行完毕会恢复常时任务')

